package com.simons.common.utils.file.office;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.simons.common.exception.CommonErrorType;
import com.simons.common.exception.CommonException;
import com.simons.common.utils.BeanTransfer;
import com.simons.common.utils.date.DateUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Excel2007 extends AbstractExcel{
	
	@Override
	public <T> List<T> read(File file, String[] fieldNames, Class<T> calzz) throws Exception {
		return this.read(file, 0, fieldNames, calzz);
	}
	
	@Override
	public <T> List<T> read(File file, int sheetAt, String[] fieldNames, Class<T> calzz) throws Exception {
		return this.read(new FileInputStream(file), sheetAt, fieldNames, calzz);
	}
	
	
	@Override
	public <T> List<T> read(InputStream input, int sheetAt, String[] fieldNames, Class<T> calzz) throws Exception {
        // 构造 XSSFWorkbook 对象，strPath 传入文件路径
        XSSFWorkbook xwb = this.getXSSFWorkbook(input);
        try{
        	return super.read(xwb, sheetAt, fieldNames, calzz);
        }catch (Exception e) {
        	log.error("读取excel操作失败" , e);
        	throw new CommonException(CommonErrorType.COMMON_ERROR, "读取excel操作失败");
        }finally{
        	IOUtils.closeQuietly(xwb);
        }
	}
	
	@Override
	public int getNumberOfSheets(File file) throws Exception {
		// 构造 XSSFWorkbook 对象，strPath 传入文件路径
		XSSFWorkbook xwb = null;
		try{
			xwb = this.getXSSFWorkbook(file);
			return xwb.getNumberOfSheets();	
		}finally{
			IOUtils.closeQuietly(xwb);
		}
        
	}

	@Override
	public int getSheetBySheetName(File file, String SheetName) throws Exception {
		XSSFWorkbook xwb = null;
		try{
			xwb = this.getXSSFWorkbook(file);
			return xwb.getSheetIndex(SheetName);
		}finally{
			IOUtils.closeQuietly(xwb);
		}
		
	}
	
	@Override
	public int getSheetBySheetName(InputStream input, String SheetName) throws Exception {
		XSSFWorkbook xwb = null;
		try{
			xwb = this.getXSSFWorkbook(input);
			return xwb.getSheetIndex(SheetName);
		}finally{
			IOUtils.closeQuietly(xwb);
		}
		
	}
	
	private XSSFWorkbook getXSSFWorkbook(File file) throws Exception{
		InputStream input = new FileInputStream(file);
		return this.getXSSFWorkbook(input);
	}
	
	/**
	 * 根据inputstream创建XSSFWorkbook
	 * @param input
	 * @return
	 * @throws IOException
	 * @throws CommonException 
	 */
	private XSSFWorkbook getXSSFWorkbook(InputStream input) throws Exception{
		try{
			return new XSSFWorkbook(input);
		}
		catch (Exception e) {
			log.error("workBook实例创建失败" , e);
			throw new CommonException(CommonErrorType.COMMON_ERROR, "workBook实例创建失败");
		}finally{
			IOUtils.closeQuietly(input);
		}
		
	}

	@Override
	public <T> void write(OutputStream out, String sheetName, String[] fieldNames, String[] heards,
			Collection<T> dataList) throws NoSuchMethodException, SecurityException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException, IOException {
		SXSSFWorkbook workbook = this.writeToWorkbook(sheetName, fieldNames, heards, dataList);
		try {
			workbook.write(out);
		} finally {
			IOUtils.closeQuietly(workbook);
		}		
	}

	/**
	 * 分页写进sheet信息
	 */
	@Override
	public <T> SXSSFWorkbook writeToWorkBook(Workbook workbook, String sheetName, String[] fieldNames, String[] heards,
			Collection<T> dataList) throws NoSuchMethodException, SecurityException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException, IOException {
		return this.writeToWorkbook((SXSSFWorkbook)workbook, sheetName, fieldNames, heards, dataList);
	}
	
	/**
	 * 不匹配枚举的，导出信息
	 * @param workbook
	 * @param sheetName
	 * @param fieldNames
	 * @param heards
	 * @param dataList
	 * @return
	 */
	private <T> SXSSFWorkbook writeToWorkbook(SXSSFWorkbook workbook, String sheetName,String[] fieldNames, String[] heards, Collection<T> dataList){
		return this.writeToWorkbook(workbook, sheetName, fieldNames, heards, dataList, null);
	}
	
	/**
	 * 设置基本的单个sheet的workBook信息
	 * @param workbook
	 * @param sheetName
	 * @param fieldNames
	 * @param heards
	 * @param dataList
	 * @param enumsMap
	 * @return
	 */
	private <T> SXSSFWorkbook writeToWorkbook(SXSSFWorkbook workbook, String sheetName,String[] fieldNames, String[] heards, Collection<T> dataList, Map<String, Map<String, String>> enumsMap){
		// 根据当前工作表数量创建相应编号的工作表
				SXSSFSheet sheet = workbook.createSheet(sheetName);
				SXSSFRow headRow = sheet.createRow(0);
				// 添加表格标题
				for (int i = 0; i < heards.length; i++) {
					SXSSFCell cell = headRow.createCell(i);
					cell.setCellType(CellType.STRING);
					cell.setCellValue(heards[i]);
					// 设置字体加粗
					CellStyle cellStyle = workbook.createCellStyle();
					Font font = workbook.createFont();
					cellStyle.setFont(font);
					// 设置自动换行
					cellStyle.setWrapText(true);
					cell.setCellStyle(cellStyle);
					// 设置单元格宽度
					sheet.setColumnWidth(i, heards[i].length() * 1000);
				}

				Iterator<T> it = dataList.iterator();
				int i = 0;
				// 添加表格内容
				while (it.hasNext()) {
					i++;
					T target = it.next();
					
					Object mapTarget=new HashMap<String, Object>();
					
					if (target instanceof Map<?, ?>){
						mapTarget=target;
					}else{
						mapTarget = BeanTransfer.beanToMap(target);
					}
					
					SXSSFRow row = sheet.createRow(i);
					// 遍历属性列表
					for (int j = 0; j < fieldNames.length; j++) {
						// 通过反射获取属性的值域
						String fieldName = fieldNames[j];
						
						if (fieldName == null) {
							continue; // 过滤serialVersionUID属性
						}
						
						Object result = ((Map<?, ?>) mapTarget).get(fieldName);
						SXSSFCell cell = row.createCell(j);
						String cellResult = toString(result);
						cell.setCellValue(cellResult);
						// 如果是日期类型则进行格式化处理
						if (result != null && result instanceof Date) {
							cell.setCellValue(DateUtils.format((Date) result));
						}
						// 如果存在enum则替换成enum方式
						if (enumsMap != null && enumsMap.get(fieldName) != null) {
							String strValue = enumsMap.get(fieldName).get(cellResult);
							log.info(strValue);
							cell.setCellValue(strValue);
						}
					}
				}
				
				return workbook;
	}
	
	/**
	 *  单个sheet的excel导出时调用的方法
	 * @param sheetName
	 * @param fieldNames
	 * @param heards
	 * @param dataList
	 * @return
	 */
	private <T> SXSSFWorkbook writeToWorkbook(String sheetName,String[] fieldNames, String[] heards, Collection<T> dataList){

		SXSSFWorkbook workbook = new SXSSFWorkbook(100);
		return this.writeToWorkbook(workbook, sheetName, fieldNames, heards, dataList);
	}
	
	public static String toString(Object obj) {
	    StringBuffer buffer = new StringBuffer();
	    if (obj != null) {
	        buffer.append(obj);
	    }
	    return buffer.toString();
	}

	@Override
	public <T> Workbook getSimpleWorkBook() {
		return new SXSSFWorkbook(100);
	}

	/**
	 * 有枚举类型的，导出
	 * @param out
	 * @param sheetName
	 * @param fieldNames
	 * @param heards
	 * @param dataList
	 * @param enumsMap
	 * @return
	 */
	@Override
	public <T> void writeByEnum(OutputStream out, String sheetName, String[] fieldNames, String[] heards,
			Collection<T> dataList, Map<String, Map<String, String>> enumMap) throws IOException {
		SXSSFWorkbook workbook = new SXSSFWorkbook(100);
		this.writeToWorkbook(workbook, sheetName, fieldNames, heards, dataList, enumMap);
		try {
			workbook.write(out);
		} finally {
			IOUtils.closeQuietly(workbook);
		}		
		
	}
}
